package cate.game.role.bag;

import cate.common.table.item.IBagItemTpl;
import cate.common.util.GameResult;
import cate.game.client.msg.MergeMsgSender;
import cate.game.res.RewardShow;
import cate.game.role.bag.item.BaseBagItem;
import cate.game.util.GameKit;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.*;

@SuppressWarnings("unchecked")
public class MultiTypeBagProxy {
    @JsonIgnore
    public final Map<Class<? extends BagContainer>, BagContainer> classBags;
    public int capacity;
    @JsonIgnore
    public String uid = GameKit.uid();
    @JsonIgnore
    private String bagName;

    @JsonIgnore
    public String getUid() {
        return uid;
    }

    @JsonIgnore
    public String getBagName() {
        return bagName;
    }

    @JsonProperty("list")
    public List<Object> getAllItems(){
        List<Object> list = new ArrayList<>();
        classBags.values().forEach(e -> list.addAll(e.getList()));
        return list;
    }

    public MultiTypeBagProxy(String bagName, BagContainer ... bags) {
        classBags = new HashMap<>();
        this.bagName = bagName;
        int ca = 999;
        for (BagContainer bag : bags) {
            classBags.put(bag.getClass(), bag);
            ca = Math.max(ca, bag.calcCapacity());
        }
        this.capacity = ca;
    }

    public MultiTypeBagProxy(String bagName, int capacity, BagContainer<?>... bags) {
        this.bagName = bagName;
        this.capacity = capacity;
        classBags = new HashMap<>();
        for (BagContainer<?> bag : bags) {
            classBags.put(bag.getClass(), bag);
        }
    }

    public long count(Class<?> clazz, int tid) {
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return 0;
        }
        return bag.count(tid);
    }

    public IBagItemTpl getItemTpl(Class<?> clazz, int tid) {
        BagContainer<?> bag = classBags.get(clazz);
        if (bag != null) {
            return bag.getItemTpl(tid);
        }
        return null;
    }

    public <T> T getItem(String uid, Class<?> clazz, Class<T> eclazz) {
        BagContainer<?> bag = classBags.get(clazz);
        if (bag != null) {
            return (T) bag.getItem(uid);
        }
        return null;
    }

    public <T extends BaseBagItem> List<T> getList(Class<?> clazz, Class<T> eclazz) {
        BagContainer<T> bag = classBags.get(clazz);
        if (bag != null) {
            return bag.getList();
        }
        return Collections.emptyList();
    }

    private int itemSize() {
        return (int) classBags.values().stream().mapToLong(BagContainer::itemSize).sum();
    }

    /** 添加 */
    public <E extends BaseBagItem> GameResult<Void> addItem(Class<?> clazz, E item, MergeMsgSender sender) {
        GameResult<Void> r = addItemCheck(clazz, item.tid, item.num);
        if (!r.ok()) {
            return r;
        }
        BagContainer<E> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        return bag.addItem(item, sender);
    }

    /** 添加 */
    public GameResult<Void> addItem(Class<?> clazz, int tid, long num, MergeMsgSender sender) {
        GameResult<Void> r = addItemCheck(clazz, tid, num);
        if (!r.ok()) {
            return r;
        }
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        return bag.addItem(tid, num, sender);
    }

    /** 添加 */
    public <E extends BaseBagItem> GameResult<Void> addItems(Class<?> clazz, List<E> items, MergeMsgSender sender) {
        GameResult<Void> r = new GameResult<>();
        if (gridEmpty() < items.size()) {
            return r.fail("背包已满");
        }
        BagContainer<E> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        return bag.addItems(items, sender);
    }

    public GameResult<Void> addItemCheck(Class<?> clazz, int templateId, long num) {
        GameResult<Void> r = new GameResult<>();
        if (num < 0) {
            return r.fail("非法数据");
        }
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        IBagItemTpl tpl = bag.getItemTpl(templateId);
        if (tpl == null) {
            return r.fail("物品不存在");
        }
        int itemSize = itemSize();
        // 剩余的格子够物品数量，那么必然是可以添加的
        long leftGridNum = (this.capacity - itemSize) * (tpl.unique() ? 1 : tpl.getPileMax());
        if (leftGridNum >= num) {
            return r.success();
        } else if (tpl.unique()) {
            return r.fail("背包已满");
        }
        // 接下来获取可用的总数量
        for (int i = 0; i < itemSize; i++) {
            BaseBagItem item = bag.getList().get(i);
            if (item.tid != templateId || item.getTpl(bag.getRole().toPlayBuildContext()).unique() || item.unique()) {
                continue;
            }
            // 该物品格子的剩余可堆叠数量
            leftGridNum += tpl.getPileMax() - item.num;
            if (leftGridNum >= num) {
                return r.success();
            }
        }
        return r.fail("背包已满");
    }

    /** 完全空的格子 */
    public int gridEmpty() {
        return this.capacity - itemSize();
    }

    /** 移除背包中的指定物品 */
    public GameResult<RewardShow> removeItem(Class<?> clazz, String uid, MergeMsgSender sender) {
        GameResult<RewardShow> r = new GameResult<>();
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        return bag.removeItem(uid, sender);
    }

    /** 删除或扣除 */
    public GameResult<RewardShow> removeItem(Class<?> clazz, int tid, long num, MergeMsgSender sender) {
        GameResult<RewardShow> r = new GameResult<>();
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        return bag.removeItem(tid, num, sender);
    }

    /** 根据唯一id来删除 */
    public GameResult<RewardShow> removeItemByUid( Class<?> clazz,
            String uid, long num, MergeMsgSender sender) {
        GameResult<RewardShow> r = new GameResult<>();
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        return bag.removeItemByUid(uid, num, sender);
    }

    public GameResult<RewardShow> notReallyRemove(Class<?> clazz, String uid, MergeMsgSender sender) {
        GameResult<RewardShow> r = new GameResult<>();
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        return bag.notReallyRemove(uid, sender);
    }

    public GameResult<RewardShow> notReallyRemove(Class<?> clazz, int tid, long num, MergeMsgSender sender) {
        GameResult<RewardShow> r = new GameResult<>();
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        return bag.notReallyRemove(tid, num, sender);
    }

    public GameResult<RewardShow> notReallyRemoveItemByUid(Class<?> clazz, String uid, long num, MergeMsgSender sender) {
        GameResult<RewardShow> r = new GameResult<>();
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return r.fail("非法数据");
        }
        return bag.notReallyRemoveItemByUid(uid, num, sender);
    }

    public void forGmAddCapacity(Class<?> clazz) {
        capacity++;
        BagContainer<?> bag = classBags.get(clazz);
        if (bag == null) {
            return;
        }
        bag.forGmAddCapacity();
    }
}
